package com.orhanobut;

import android.app.Application;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.util.Log;

import com.orhanobut.logger.AndroidLogAdapter;
import com.orhanobut.logger.CsvFormatStrategy;
import com.orhanobut.logger.DiskLogAdapter;
import com.orhanobut.logger.FormatStrategy;
import com.orhanobut.logger.Logger;
import com.orhanobut.logger.PrettyFormatStrategy;
import com.orhanobut.secrity.CrcDex;
import com.orhanobut.secrity.SignCheck;

import androidx.annotation.Nullable;

/**
 * 存放一些基本常量供使用
 * 初始化
 *
 * @author rui.yang
 */
public class MyLoggerConfig {
    /**
     * 全局上下文信息
     */
    protected static Application APPLICATION;

    /**
     * 这个是单例的类，用于处理日志的初始化
     */
    private static MyLoggerConfig loggerConfig = new MyLoggerConfig();

    private MyLoggerConfig() {

    }

    public static MyLoggerConfig getInstance() {
        return loggerConfig;
    }

    /**
     * 标签，默认 MyLibLogger
     */
    private String tag = "MyLibLogger";
    /**
     * 是否显示线程信息，默认不显示
     */
    private boolean showThreadInfo = true;
    /**
     * 方法显示行数，默认不打印
     */
    private int methodCount = 1;
    /**
     * 隐藏内部方法调用偏移量，默认跳过LogUtil中调用方法
     */
    private int methodOffset = 1;
    /**
     * 是否将日志写入到本地磁盘中,默认不显示，日志文件地址： Environment.getExternalStorageDirectory().getAbsolutePath() + "logger"
     */
    private boolean writeFile = false;

    /**
     * 设置上下文的，Toast中需要使用
     * 必须调用
     *
     * @param application
     * @return
     */
    public MyLoggerConfig context(Application application) {
        APPLICATION = application;
        return this;
    }

    /**
     * 设置当前使用的日志的 TAG
     * 非必须
     *
     * @param tag
     * @return
     */
    public MyLoggerConfig tag(String tag) {
        this.tag = tag;
        return this;
    }

    /**
     * 是否写入到文件中
     * 如果设置就下面其他设置将会无效
     * 不管是否是DEBUG模式均会写入到日志当中
     * 日志文件默认大小500K
     * 非必须
     *
     * @param writeFile writeFile
     * @return NewLoggerConfig
     */
    public MyLoggerConfig isWriteLogToFile(boolean writeFile) {
        this.writeFile = writeFile;
        return this;
    }

    /**
     * 是否显示线程信息
     * 非必须
     *
     * @param showThreadInfo showThreadInfo
     * @return NewLoggerConfig
     */
    public MyLoggerConfig showThreadInfo(boolean showThreadInfo) {
        this.showThreadInfo = showThreadInfo;
        return this;
    }

    /**
     * 线程日志调用方法的顺序栈,
     * 比如：
     * 1、在onCreate方法中调用init方法，在inti方法调用LogUtil.e,如果是 3 层的话，那么顺序栈 onCreate-init-LogUtil中的e方法
     * 2、在onCreate方法中调用init方法，在inti方法调用LogUtil.e,如果是 2 层的话，那么顺序栈 init-LogUtil中的e方法
     * 非必须
     *
     * @param methodCount methodCount
     * @return NewLoggerConfig
     */
    public MyLoggerConfig methodCount(int methodCount) {
        this.methodCount = methodCount;
        return this;
    }

    /**
     * 设置打印信息的偏移量， 默认是1层，这样可以跳过一层方法
     * 比如:
     * 在onCreate方法中调用init方法，在inti方法调用LogUtil.e,如果是 2 层的话,
     * 此时如果偏移量是 0，那么打印的栈信息是 init-LogUtil.e方法
     * 此时如果偏移量是 1，那么打印的栈信息是 onCreate-init,将最近的一层方法给跳过去
     * 非必须
     *
     * @param methodOffset methodOffset
     * @return NewLoggerConfig
     */
    public MyLoggerConfig methodOffset(int methodOffset) {
        this.methodOffset = methodOffset;
        return this;
    }

    public MyLoggerConfig checkSign(String sign){
        SignCheck signCheck = new SignCheck(APPLICATION, sign);
        if(signCheck.check()) {
            //TODO 签名正常
            Log.e("TAG", "onCreate>>>>:签名正常");
        }else {
            //TODO 签名不正确
            Log.e("TAG", "onCreate>>>>:签名不正确");
            System.exit(0);
        }

        return this;
    }

    public MyLoggerConfig crc(String crc){
        CrcDex.crc(APPLICATION, crc);
        return this;
    }

    /**
     * 初始化最终构建方法
     * 必须调用
     */
    public void build() {
        if (!writeFile) {
            FormatStrategy formatStrategy = PrettyFormatStrategy.newBuilder()
                    .showThreadInfo(showThreadInfo)
                    .methodCount(methodCount)
                    .methodOffset(methodOffset)
                    .tag(tag)
                    .build();

            //如果是release版本不打印日志,这里做统一控制
            Logger.addLogAdapter(new AndroidLogAdapter(formatStrategy) {
                @Override
                public boolean isLoggable(int priority, @Nullable String tag) {
                    return checkIsDebug(APPLICATION);
                }
            });
        } else {
            FormatStrategy formatStrategy = CsvFormatStrategy.newBuilder()
                    .tag(tag)
                    .build();

            //如果是release版本不打印日志,这里做统一控制
            Logger.addLogAdapter(new DiskLogAdapter(formatStrategy){
                @Override
                public boolean isLoggable(int priority, @Nullable String tag) {
                    return checkIsDebug(APPLICATION);
                }
            });
        }
    }

    /**
     * 检测app是否为debug版本
     *
     * @param context
     * @return
     */
    private boolean checkIsDebugVersion(Context context) {
        return (context.getApplicationInfo().flags
                & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
    }

    /**
     * java法检测是否连上调试器
     *
     * @return
     */
    private boolean checkIsDebuggerConnected() {
        return android.os.Debug.isDebuggerConnected();
    }

    /**
     * 检测app是否为debug版本
     *
     * @param context
     * @return app是否为debug版本
     */
    public boolean checkIsDebug(Context context) {
        return checkIsDebugVersion(context) || checkIsDebuggerConnected();
    }
}
